home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Documentation / Tech Notes & Articles / Recipes / UI & Events / Basic Event Handling < prev    next >
Encoding:
Text File  |  1995-11-07  |  11.7 KB  |  281 lines  |  [TEXT/ttxt]

  1. OpenDoc™ Recipes
  2.  
  3. Basic Event Handling
  4. By The OpenDoc Design Team
  5. November, 1995
  6.  
  7.  
  8. © 1993-1995  Apple Computer, Inc. All Rights Reserved.
  9. Apple, the Apple logo, and Macintosh are registered trademarks of Apple Computer, Inc.
  10. Mac and OpenDoc are trademarks of Apple Computer, Inc. 
  11.  
  12.  
  13. Introduction
  14.  
  15. This document describes the basics of event distribution to parts. It describes the events a part will need to handle, but does not describe in great detail what should be done with each event. This is heavily content-dependent, and will often be apparent to Macintosh developers. This section also does not deal with semantic events.
  16.  
  17. See also:
  18.     Window Events
  19.     Mouse Events
  20.     Menus
  21.     Windows and Dialogs    
  22.     Drag and Drop
  23.     
  24. The OpenDoc shell and container applications contain an event loop, and call ODDispatcher::Dispatch() to deliver events to parts. This method takes an event record and returns a Boolean value. If the returned value is kODFalse, the shell may handle the event, otherwise a part, or the dispatcher itself has handled the event.
  25.  
  26. The dispatcher contains a table of dispatch modules. The dispatcher locates a dispatch module for a given event, and the dispatch module calls one of the following ODPart methods, shown here in IDL:
  27.  
  28.     void Draw(in ODFacet facet,
  29.                in ODShape invalidShape);
  30.     ODBoolean HandleEvent(inout ODEventData event,
  31.                    in ODFrame frame,
  32.                 in ODFacet facet,
  33.                 inout ODEventInfo eventInfo);
  34.  
  35. New in DR2: ODEventInfo has the following definition:
  36.  
  37. struct ODEventInfo
  38. {
  39.     ODFrame embeddedFrame;
  40.     ODFacet embeddedFacet;
  41.     ODPoint where;
  42.     ODBoolean propagated;
  43. };
  44.  
  45. New in DR2:  Since the DR1 release of OpenDoc, HandleEventInEmbedded,  MouseEnter, MouseWithin and MouseLeave have been removed. Instead, HandleEvent takes the extra eventInfo parameter which contains the embedded frame and facet which were passed to HandleEventInEmbedded, and the ODPoint which was passed to MouseEnter and MouseWithin.
  46.  
  47. The frame and facet parameters of HandleEvent() may be kODNULL, depending on the kind of event. The embeddedFrame and embeddedFacet fields of ODEventInfo will also be kODNULL except for certain kinds of events.  See the notes on particular events below.
  48.  
  49.  
  50.  
  51. Standard Macintosh Events
  52.  
  53. Part editors must handle the following events, which correspond to standard Macintosh events:
  54.  
  55.     kODEvtNull
  56.      kODEvtMouseDown
  57.      kODEvtMouseUp
  58.      kODEvtKeyDown
  59.      kODEvtKeyUp
  60.      kODEvtAutoKey
  61.      kODEvtUpdate
  62.      kODEvtActivate
  63.      kODEvtOS
  64.  
  65. Additional OpenDoc Events
  66.  
  67. OpenDoc part editors must handle the following additional events:
  68.  
  69.     kODEvtMenu        // Mouse down in the menu bar
  70.     kODEvtWindow        // Mouse down in the window title bar. Close menu item.
  71.     kODEvtMouseEnter    // Mouse moved into a frame for the first time
  72.     kODEvtMouseWithin    // Mouse moved within a frame
  73.     kODEvtMouseLeave    // Mouse moved outside a frame
  74.     kODEvtBGMouseDown    // Mouse down in an inactive (background) document
  75.  
  76. Part editors which support embedding must also handle the following events:
  77.  
  78.     kODEvtMouseDownEmbedded    // Mouse down in a selected, bundled or iconic frame
  79.     kODEvtBGMouseDownEmbedded    // As above, in an inactive (background) document
  80.     kODEvtMouseUpEmbedded        // Mouse up in a selected, bundled or iconic frame
  81.     kODEvtMouseDownBorder        // Mouse down in the active frame border
  82.  
  83. Read-Only Documents
  84.  
  85. Note: Part Editors will need to disable certain portions of their event handling when a draft is read-only. See the Init Part and Externalize recipe for information on draft permissions.
  86.  
  87. Standard Macintosh Events
  88.  
  89. Idle Time (Null Events)
  90.  
  91. In order to receive null events (i.e. idle time), parts must call ODDispatcher::RegisterIdle(), specifying  the part (actually part wrapper), a frame and an idle frequency.  
  92.             
  93.     session->GetDispatcher(ev)->RegisterIdle(ev,  fPartWrapper, aFrame, kMyIdleFrequency);
  94.  
  95. The frame can be kODNULL. If frames are registered, the part will receive a null event for each frame registered. The idle frequencies are used in the computation of the sleep time passed to WaitNextEvent.  Idle frames might be registered in Part::DisplayFrameAdded() and Part::DisplayFrameConnected(), or perhaps in Part::FacetAdded(). Idle frames should be unregistered before the frame is destroyed, such as in DisplayFrameClosed() and DisplayFrameRemoved().
  96.  
  97.     session->GetDispatcher(ev)->UnregisterIdle(ev, fPartWrapper, oldFrame );
  98.  
  99. Example of handling  null events:
  100.         
  101.         case kODEvtNULL:
  102.             {
  103.                 ClockFrame* clockFrame = (ClockFrame*) frame->GetPartInfo(ev);
  104.                 if (clockFrame)
  105.                     clockFrame->Idle(ev, event);
  106.                 else
  107.                     _fClockPart->Idle(ev, event);
  108.                 wasHandled = kODTrue;
  109.                 break;
  110.             }
  111.  
  112. void ClockDialogFrame::Idle(Environment* ev, ODEventData* event)
  113. {
  114.     if (IsDialogEvent((const EventRecord *)event))
  115.     {
  116.         short itemHit;
  117.         DialogPtr dialog;
  118.         ODBoolean wasHandled = DialogSelect((const EventRecord *)event, &dialog, &itemHit);
  119.     }
  120. }
  121.  
  122.  
  123. Mouse Events
  124.  
  125. In addition to the standard mouse down and mouse up events, part editors which support embedding must deal with mouse events in embedded frames which are selected, bundled or viewed as icons or thumbnails. Part editors must also handle special background mouse events to support Drag and Drop. See Mouse Events and Drag and Drop recipes.
  126.  
  127. Keyboard Events
  128.  
  129. Keyboard events go to the frame with the keyboard focus, with the exception of the Page Up, Page Down, Home and End keys, which will go to the frame with the scrolling focus, if there is one.
  130.  
  131. Update Events
  132.  
  133. Update events are not passed to Part::HandleEvent(). Rather ODPart::Draw() will be called once for each facet in the window. See the sample code and the Imaging recipes for examples of drawing.
  134.  
  135. Activate Events
  136.  
  137. Activate events are also delivered to each facet in a window, using Part::HandleEvent(). The facets are traversed  bottom up. i.e. the root facet comes last.
  138.  
  139.         case kODEvtActivate:
  140.             wasHandled = true; // actually ignored by dispatcher
  141.             if ((event->modifiers & activeFlag ) != 0)
  142.                 clockFrame->ActivatingWindow(ev, facet, event);
  143.             else
  144.                 clockFrame->DeactivatingWindow(ev, facet, event);
  145.             break;
  146.  
  147. void ClockTimeFrame::ActivatingWindow(Environment* ev, ODFacet* facet, ODEventData* event) 
  148. {
  149.     if (fNeedsFoci)
  150.     {
  151.         this->Activate(ev);    // Request Foci etc. See Activation recipe
  152.     }
  153.     fNeedsFoci = kODFalse;
  154. }
  155. void ClockTimeFrame::DeactivatingWindow(Environment* ev, ODFacet* facet, ODEventData* event)
  156. {
  157.     if (fHasFoci)
  158.     {
  159.         fNeedsFoci = kODTrue; // I want to be active when my window is
  160.     }
  161.     else
  162.         fNeedsFoci = kODFalse;
  163. }
  164.  
  165.  
  166. Disk Events
  167.  
  168. Currently, disk events are not distributed to parts.
  169.  
  170. OS Events
  171.  
  172. Suspend/Resume events are delivered to each facet in each window using Part::HandleEvent(). 
  173. A part should hide dialogs and palettes when switching to the background, and show them again when returning to the foreground.
  174.  
  175. Mouse Moved events are turned in the events kODEvtMouseEnter, kODEvtMouseWithin and kODEvtMouseLeave which are described in the next section.
  176.  
  177. Additional OpenDoc Events
  178.  
  179. Menu Events
  180.  
  181. OpenDoc converts a mouse down in the menu bar, or its command-key equivalent,  into a menu event of type kODEvtMenu.
  182.  
  183. The message field of the event record contains the result returned by MenuSelect() or MenuKey(). i.e. the menu is in the high word, and the item in the low word. The part can obtain a command number from the menu and item using ODMenuBar::GetCommand().
  184.         
  185. See Menus recipe for more details.
  186.  
  187. Window Events
  188.  
  189. Events in the title bar of a window  are delivered to the root part of that window as an event of type kODEvtWindow. The message field of the event contains the part code, as returned by FindWindow(). See Window Events recipe.
  190.  
  191. Mouse Moved Events
  192.  
  193. New in DR2: The following  ODPart methods have been removed:
  194.  
  195. void MouseEnter(in ODFacet facet,
  196.            in ODPoint where);
  197. void MouseWithin(in ODFacet facet,
  198.            in ODPoint where);
  199. void MouseLeave(in ODFacet facet);
  200.  
  201. Instead there are three new events kODEvtMouseEnter, kODEvtMouseWithin and kODEvtMouseLeave which are passed to HandleEvent() along with a frame and facet. The "where" value is included in the eventInfo struct, and contains a point in local (frame) coordinates.
  202.  
  203. OpenDoc tracks cursor movement (with the mouse button up), and delivers a kODEvtMouseEnter event to the frame under the mouse when the cursor first moves into one of its facets.  If the mouse moves within a frame, a kODEvtMouseWithin event is sent, and when the mouse moves outside of the facet, a kODEvtMouseLeave event is sent.  A part editor will typically change the cursor on receiving a kODEvtMouseEnter and kODEvtMouseWithin, and set it to the arrow on kODEvtMouseLeave.
  204.  
  205. These events are triggered by the shell calling ODDispatcher::GetMouseRegion() to determine a sleep region to pass to WaitNextEvent(). The region is only recomputed when it has been invalidated, such as when the shell receives a mouseMoved event from the system. Part Editors can also invalidate the region by calling the ODDispatcher method:
  206.  
  207.     void InvalidateFacetUnderMouse();
  208.  
  209. By default, OpenDoc computes a mouse region containing  just the cursor location.  If the cursor is motionless within a facet, the shell application can go to sleep. A part editor can make this region larger by calling  the ODDispatcher method:
  210.  
  211.    void SetMouseRegion(in ODRgnHandle area);
  212.  
  213. The region is in global (screen) coordinates.
  214.  
  215. In a future release, if the cursor is not within any facet, OpenDoc should compute a suitably large sleep region  (i.e. screen minus content regions of OpenDoc windows).
  216.  
  217. A containing part is responsible for for setting the cursor to the hand cursor over the active border:
  218.  
  219.         case kODEvtMouseWithin:
  220.         {
  221.             // Note: ODFacet::ActiveBorderContainsPoint takes frame coordinates
  222.             ODBoolean cursorInActiveBorder = kODFalse;
  223.             ODArbitrator* fArbitrator = _fSession->GetArbitrator(ev);
  224.             ODFrame* activeFrame = fArbitrator->AcquireFocusOwner(ev, _fSelectionFocus);
  225.             if (activeFrame) 
  226.             {
  227.                 ODFrameFacetIterator* iter = activeFrame->CreateFacetIterator(ev);
  228.                 ODReleaseObject(ev, activeFrame);
  229.                     
  230.                 TempODTransform windowFrameXForm = 
  231.                     facet->AcquireWindowFrameTransform(ev, kODNULL);
  232.                 ODPoint windowMouse = windowFrameXForm->TransformPoint(ev, &(eventInfo->where));
  233.                     
  234.                 for (ODFacet* facet = iter->First(ev); iter->IsNotComplete(ev);
  235.                         facet = iter->Next(ev))
  236.                 {
  237.                     TempODTransform xForm = facet->AcquireWindowFrameTransform(ev, kODNULL);
  238.                     ODPoint framePoint = xForm->InvertPoint(ev, &windowMouse);
  239.                         
  240.                     if (facet->ActiveBorderContainsPoint(ev,&framePoint,kODNULL))
  241.                     {
  242.                         cursorInActiveBorder = kODTrue;
  243.                         break;
  244.                     } 
  245.                 }
  246.                 ODDeleteObject(iter);
  247.             }
  248.             if (cursorInActiveBorder)
  249.             {
  250.                 ODSLong savedRefNum;
  251.                 BeginUsingLibraryResources(savedRefNum);
  252.                 SetCursor(*GetCursor(283)); // Hand Cursor 
  253.                 EndUsingLibraryResources(savedRefNum);
  254.             }
  255.             else
  256.                 SetCursor(*GetCursor(crossCursor)); // For now. 
  257.                     
  258.         }
  259.         handled = kODTrue;
  260.         break;
  261.  
  262. Mouse Events in Embedded Frames
  263.  
  264. See Mouse Events recipe.
  265.     
  266. Special Considerations
  267.  
  268. The Modal Focus
  269.  
  270. Some events are constrained by the modal focus. A mouse click outside the frame with the modal focus will be sent to the modal focus frame, but a click in an embedded  frame within the modal focus frame will still go to the embedded frame.  When the user clicks outside the modal frame, a facet of kODNULL is passed to HandleEvent(). The part editor should check for this value, and beep or dismiss the dialog as desired.
  271.  
  272. See Dialogs recipe for more about the modal focus.
  273.  
  274. The Mouse Focus (New in DR4) 
  275.  
  276. For modal situations, like a polygon drawing tool, the mouse focus captures mouse down, mouse up and mouse moved events. See Mouse Events recipe.
  277.  
  278. Propagating Events
  279.  
  280. This feature of OpenDoc is not likely to be used by most parts. If a containing part sets the “DoesPropagateEvents” property of an embedded frame, the containing part will receive events not handled by the embedded frame, via the HandleEvent() method.  
  281.